
// 动画的三种方式

// 所有的软件基本都会对齐到60帧 --> 16ms
// 不推荐 --> 比较不可控，容易积压
// setInterval(() => {}, 16)

// 只会执行一次，需要函数(Tick)
// let tick = () => {
//   // 执行的其他东西 xxx
//   // 最后再调用setTimeout
//   setTimeout(tick, 16)
// }

// 现代浏览器支持 requestAnimationFrame (推荐使用)
// 浏览器执行下一帧的时候执行这个代码 与浏览器的帧率相关
// 比较好的可以操作时间线 帧率
// let tick = () => { 
//   // 执行的其他东西 xxx
//   // 最后再调用requestAnimationFrame
//   requestAnimationFrame(tick)
//   // let handle = requestAnimationFrame(tick)
//   // 结束动画 避免资源浪费
//   // cancelAnimationFrame(handle)
// }



// --------------------------------------------------
// 保证私有变量，除animation 外都访问不到
const TICK = Symbol("tick");
const TICK_HANDLER = Symbol("tick-handler");
const ANIMATIONS = Symbol("animations");
const START_TIME = Symbol("start-time");
const PAUSE_START = Symbol("pause-start");
const PAUSE_TIME = Symbol("pause-time");


export class Timeline {
  constructor() {
    this.state = "inited";
    // 一般来说 timeline 里面会有animation的队列
    this[ANIMATIONS] = new Set();
    this[START_TIME] = new Map();
  }

  start() { // 启动
    if (this.state !== "inited")
      return;
    console.log('启动123')
    this.state = "started";
    let startTime = Date.now();
    this[PAUSE_TIME] = 0;
    this[TICK] = () => {
      // console.log('tick')
      // let t = Date.now() - startTime
      let now = Date.now();
      for(let animation of this[ANIMATIONS]) {
        let t; // 保存时间 防止超过额定值
        // 动态的向timeline添加animation 可以不需要频繁的开启、重置
        if (this[START_TIME].get(animation) < startTime)
          t = now - startTime - this[PAUSE_TIME] - animation.delay;
        else
          t = now - this[START_TIME].get(animation) - this[PAUSE_TIME] - animation.delay;

        if (animation.duration < t) { // 当t 大于 duration时停止
          this[ANIMATIONS].delete(animation);
          t = animation.duration;
        }

        if(t > 0) // 算上delay
          animation.receive(t);
      }
      // 存起来，方便控制启动、暂停
      this[TICK_HANDLER] = requestAnimationFrame(this[TICK]);
    }
    this[TICK]();
  }
  // stop() {} // 正常来说Timeline 不会有stop 只需要start
  // get rate() {} // 播放速率 (倍数，暂时不写)
  // set rate() {}

  pause() { // 暂停
    if (this.state !== "started")
      return;
    this.state = "paused";
    // 需要记 暂停开始的时间、暂停截止的时间
    this[PAUSE_START] = Date.now();
    cancelAnimationFrame(this[TICK_HANDLER]);
  }

  resume() { // 恢复
    if (this.state !== "paused")
      return;
    this.state = "started";
    this[PAUSE_TIME] += Date.now() - this[PAUSE_START];
    this[TICK]();
  }

  reset() { // 重启
    this.pause();
    this.state = "inited";
    // let startTime = Date.now();
    this[PAUSE_TIME] = 0;
    this[ANIMATIONS] = new Set();
    this[START_TIME] = new Map();
    this[PAUSE_START] = 0;
    this[TICK_HANDLER] = null;
    // this.start();
    // this[TICK]();
  }

  add(animation, startTime = Date.now()) {
    // if (arguments.length < 2) {
    //   startTime = Date.now();
    // }
    this[ANIMATIONS].add(animation); // 添加animation
    this[START_TIME].set(animation, startTime); // 动画开始时，获取添加(开始)的时间 delay
  }

}

// 属性动画
export class Animation {
  // 前五个一定要有，动画最基本需要
  constructor(object, property, startValue, endValue, duration, delay, timingFunction, template) {
    timingFunction = timingFunction || (v => v);
    template = template || (v => v);

    this.object = object;
    this.property = property;
    this.startValue = startValue;
    this.endValue = endValue;
    this.duration = duration;
    this.delay = delay;
    this.timingFunction = timingFunction;
    this.template = template;
  }

  receive(time) { // 执行
    console.log(time);
    let range = (this.endValue - this.startValue); // 变化区间
    // 时间、速率变化 ---> (暂时)均匀变化
    let progress = this.timingFunction(time / this.duration)
    this.object[this.property] = this.template(this.startValue + range * progress);
  }

}

